Skip to content

release: dev → prod — 2026-07-17 #3 (booking lifecycle + request-list perf + refund hardening) - #1016

Merged
teetangh merged 3 commits into
prodfrom
release/dev-to-prod-2026-07-17-3
Jul 17, 2026
Merged

release: dev → prod — 2026-07-17 #3 (booking lifecycle + request-list perf + refund hardening)#1016
teetangh merged 3 commits into
prodfrom
release/dev-to-prod-2026-07-17-3

Conversation

@teetangh

Copy link
Copy Markdown
Contributor

Third release of 2026-07-17, completing the day's booking-and-money wave.

#1002 — booking lifecycle correctness. Cancelled webinars and classes can no longer be resurrected by a late allocation (WHERE-guarded status transitions); class partial reschedules now reschedule only the selected sessions instead of silently escalating to the whole class; the tentative-slot cleanup measures its grace period from the last write and guards group events, so rescheduled slots are no longer swept immediately; org-sponsored re-allocations no longer double-debit BookingUtilization; and the appointment-reminder job — which had no scheduler at all — now runs hourly via GitHub Actions.

#1000 — request-list performance (#997 phases 0–1). The PENDING request endpoints replace their deep include trees with narrow field-verified selects (the old tree joined consultant domain/subdomain/tag M2Ms and per-slot user M2Ms no consumer reads, and over-shared user PII), with shared SELECT fragments in lib/booking/list-selects.ts; Auto Allocate now runs the server's hardened allocator instead of downloading the full scheduling period to the browser.

#1015 — refund hardening (review follow-up to #1014). The gateway-id binding now merges refund metadata instead of replacing it (the replacement destroyed audit keys on every refund), and empty gateway refund ids are normalized to absent rather than masquerading as real ids.

No database schema changes or migrations are included.

🤖 Generated with Claude Code

teetangh and others added 3 commits July 17, 2026 19:15
…ial reschedule, cleanup guards, utilization re-key, reminder scheduler (#1002)

* fix(booking): lifecycle correctness — cancelled-event CAS, class partial reschedule, cleanup guards, utilization re-key, reminder scheduler

C2: webinar/class allocation now rides WHERE-guarded transitions
(EVENT_ALLOWED_FROM) so a cancel racing an allocation can no longer
resurrect a CANCELLED event. R1: the slotIds reschedule branch covers
CLASS, ending the silent escalation of a per-session class reschedule
to the whole class. R3: tentative-slot cleanup measures grace from the
last write (rescheduled slots had zero grace) and skips SCHEDULED/
IN_PROGRESS webinars and classes mid-reschedule. M4: BookingUtilization
substitutes re-created appointment ids one-for-one instead of
re-debiting every re-allocation. The appointment-reminder job finally
gets a scheduler (hourly GH Actions workflow; all three layers existed
with nothing firing them).

Findings C2/R1/R3/M4 + reminder gap from the 2026-07-17 booking audit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(booking): add updatedAt to the cleanup-guard fixture

The sweep now measures grace from updatedAt; the #829 guard fixture
predated the field and threw before the delete ran.

Part of #1002.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…ocate (#1000)

* perf(bookings): narrow PENDING request queries + server-side Auto Allocate

Phase 0 (#997): the consultations/subscriptions list GETs joined
consultantProfile.domain/subDomains/tags and a per-slot user M2M that no
list consumer reads, and over-shared user PII (email/role/phone) against
the #946 allowlist direction. Replace the include trees with narrow
selects of the verified field superset and filter ownership on the
plan's indexed scalar FK. Existing composite indexes already cover the
hot path — no schema change.

Phase 1 (#997): the dialog's Auto Allocate no longer downloads the full
scheduling period of availability to run the client algorithm; it calls
the server's hardened isAuto mode (Redis locks, tz-aware caps,
initialAllocation guard, idempotent replay) and reflects the returned
appointments on the grid. AllocationAlgorithms.autoAllocate is retained
as the mode-parity test oracle until phases 2-3.

Part of #997.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(bookings): extract shared list SELECT fragments

Sonar's new-code duplication gate (25% vs 3%) flagged the select trees
copy-pasted between the two list routes; they must stay field-identical
for shared consumers, so they now live in lib/booking/list-selects.ts.

Part of #1000.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…1015)

Release #1014 review, on code from #1001:
- Phase-3a gateway-id binding replaced the Refund row's metadata JSON
  wholesale, destroying Phase-1 audit keys (initiatedByUserId, source)
  on every Razorpay refund (notes always present). Now spreads the
  reserved row's metadata under the gateway keys.
- refundId binding gains the same falsy-guard as the FAILED branch, so
  the unique non-nullable column never gets "" and the pending_
  placeholder stays matchable by reconcile-pending-refunds.
- RefundResult.gatewayRefundId is now optional and normalized with
  `|| undefined` at both return sites: absent, never "". No caller
  consumed the field; the reconcile cron keys off the DB column.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@netlify

netlify Bot commented Jul 17, 2026

Copy link
Copy Markdown

Deploy Preview for familiarise ready!

Name Link
🔨 Latest commit f6ace21
🔍 Latest deploy log https://app.netlify.com/projects/familiarise/deploys/6a5a390a89816a0008140291
😎 Deploy Preview https://deploy-preview-1016--familiarise.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 65 (🟢 up 10 from production)
Accessibility: 99 (🟢 up 3 from production)
Best Practices: 92 (🟢 up 9 from production)
SEO: 100 (no change from production)
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3862d2eb-9a37-4e53-ba2a-22eeab6d5136

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release/dev-to-prod-2026-07-17-3

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sonarqubecloud

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request optimizes the booking and payment workflows by moving auto-allocation to the server-side, narrowing Prisma queries to protect user PII, and introducing guarded status transitions for webinars and classes. It also fixes issues with per-session class reschedules, double-debiting during re-allocation, and tentative slot cleanup grace periods. Feedback is provided regarding a TypeScript compilation error in the refund operation where spreading reserved.metadata requires an explicit cast to Record<string, unknown> under strict mode.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +351 to +355
...(reserved.metadata &&
typeof reserved.metadata === "object" &&
!Array.isArray(reserved.metadata)
? reserved.metadata
: {}),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

TypeScript will raise a compilation error here under strict mode (Spread types may only be created from object types. ts(2698)) because reserved.metadata is typed as Prisma.JsonValue (which can be a primitive, array, or null) and cannot be directly spread. Casting it to Record<string, unknown> after the type guard resolves this issue.

Suggested change
...(reserved.metadata &&
typeof reserved.metadata === "object" &&
!Array.isArray(reserved.metadata)
? reserved.metadata
: {}),
...(reserved.metadata &&
typeof reserved.metadata === "object" &&
!Array.isArray(reserved.metadata)
? (reserved.metadata as Record<string, unknown>)
: {}),

@teetangh
teetangh merged commit a60e5a6 into prod Jul 17, 2026
19 of 20 checks passed
@teetangh
teetangh deleted the release/dev-to-prod-2026-07-17-3 branch July 17, 2026 14:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant